{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a target=\"_blank\" href=\"https://colab.research.google.com/github/langchain-ai/langchain/blob/master/docs/docs/integrations/callbacks/uptrain.ipynb\">\n",
    "  <img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/>\n",
    "</a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# UpTrain\n",
    "\n",
    "> UpTrain [[github](https://github.com/uptrain-ai/uptrain) || [website](https://uptrain.ai/) || [docs](https://docs.uptrain.ai/getting-started/introduction)] is an open-source platform to evaluate and improve LLM applications. It provides grades for 20+ preconfigured checks (covering language, code, embedding use cases), performs root cause analyses on instances of failure cases and provides guidance for resolving them."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## UpTrain Callback Handler\n",
    "\n",
    "This notebook showcases the UpTrain callback handler seamlessly integrating into your pipeline, facilitating diverse evaluations. We have chosen a few evaluations that we deemed apt for evaluating the chains. These evaluations run automatically, with results displayed in the output. More details on UpTrain's evaluations can be found [here](https://github.com/uptrain-ai/uptrain?tab=readme-ov-file#pre-built-evaluations-we-offer-). \n",
    "\n",
    "Selected retievers from Langchain are highlighted for demonstration:\n",
    "\n",
    "### 1. **Vanilla RAG**:\n",
    "RAG plays a crucial role in retrieving context and generating responses. To ensure its performance and response quality, we conduct the following evaluations:\n",
    "\n",
    "- **[Context Relevance](https://docs.uptrain.ai/predefined-evaluations/context-awareness/context-relevance)**: Determines if the context extracted from the query is relevant to the response.\n",
    "- **[Factual Accuracy](https://docs.uptrain.ai/predefined-evaluations/context-awareness/factual-accuracy)**: Assesses if the LLM is hallcuinating or providing incorrect information.\n",
    "- **[Response Completeness](https://docs.uptrain.ai/predefined-evaluations/response-quality/response-completeness)**: Checks if the response contains all the information requested by the query.\n",
    "\n",
    "### 2. **Multi Query Generation**:\n",
    "MultiQueryRetriever creates multiple variants of a question having a similar meaning to the original question. Given the complexity, we include the previous evaluations and add:\n",
    "\n",
    "- **[Multi Query Accuracy](https://docs.uptrain.ai/predefined-evaluations/query-quality/multi-query-accuracy)**: Assures that the multi-queries generated mean the same as the original query.\n",
    "\n",
    "### 3. **Context Compression and Reranking**:\n",
    "Re-ranking involves reordering nodes based on relevance to the query and choosing top n nodes. Since the number of nodes can reduce once the re-ranking is complete, we perform the following evaluations:\n",
    "\n",
    "- **[Context Reranking](https://docs.uptrain.ai/predefined-evaluations/context-awareness/context-reranking)**: Checks if the order of re-ranked nodes is more relevant to the query than the original order.\n",
    "- **[Context Conciseness](https://docs.uptrain.ai/predefined-evaluations/context-awareness/context-conciseness)**: Examines whether the reduced number of nodes still provides all the required information.\n",
    "\n",
    "These evaluations collectively ensure the robustness and effectiveness of the RAG, MultiQueryRetriever, and the Reranking process in the chain."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Install Dependencies"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n",
      "To disable this warning, you can either:\n",
      "\t- Avoid using `tokenizers` before the fork if possible\n",
      "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33mWARNING: There was an error checking the latest version of pip.\u001b[0m\u001b[33m\n",
      "\u001b[0mNote: you may need to restart the kernel to use updated packages.\n"
     ]
    }
   ],
   "source": [
    "%pip install -qU langchain langchain_openai langchain-community uptrain faiss-cpu flashrank"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "NOTE: that you can also install `faiss-gpu` instead of `faiss-cpu` if you want to use the GPU enabled version of the library."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Import Libraries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from getpass import getpass\n",
    "\n",
    "from langchain.chains import RetrievalQA\n",
    "from langchain.retrievers import ContextualCompressionRetriever\n",
    "from langchain.retrievers.document_compressors import FlashrankRerank\n",
    "from langchain.retrievers.multi_query import MultiQueryRetriever\n",
    "from langchain_community.callbacks.uptrain_callback import UpTrainCallbackHandler\n",
    "from langchain_community.document_loaders import TextLoader\n",
    "from langchain_community.vectorstores import FAISS\n",
    "from langchain_core.output_parsers.string import StrOutputParser\n",
    "from langchain_core.prompts.chat import ChatPromptTemplate\n",
    "from langchain_core.runnables.passthrough import RunnablePassthrough\n",
    "from langchain_openai import ChatOpenAI, OpenAIEmbeddings\n",
    "from langchain_text_splitters import (\n",
    "    RecursiveCharacterTextSplitter,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load the documents"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "loader = TextLoader(\"../../how_to/state_of_the_union.txt\")\n",
    "documents = loader.load()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Split the document into chunks"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=0)\n",
    "chunks = text_splitter.split_documents(documents)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create the retriever"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "embeddings = OpenAIEmbeddings()\n",
    "db = FAISS.from_documents(chunks, embeddings)\n",
    "retriever = db.as_retriever()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Define the LLM"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "llm = ChatOpenAI(temperature=0, model=\"gpt-4\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup\n",
    "\n",
    "UpTrain provides you with:\n",
    "1. Dashboards with advanced drill-down and filtering options\n",
    "1. Insights and common topics among failing cases\n",
    "1. Observability and real-time monitoring of production data\n",
    "1. Regression testing via seamless integration with your CI/CD pipelines\n",
    "\n",
    "You can choose between the following options for evaluating using UpTrain:\n",
    "### 1. **UpTrain's Open-Source Software (OSS)**: \n",
    "You can use the open-source evaluation service to evaluate your model. In this case, you will need to provie an OpenAI API key. UpTrain uses the GPT models to evaluate the responses generated by the LLM. You can get yours [here](https://platform.openai.com/account/api-keys).\n",
    "\n",
    "In order to view your evaluations in the UpTrain dashboard, you will need to set it up by running the following commands in your terminal:\n",
    "\n",
    "```bash\n",
    "git clone https://github.com/uptrain-ai/uptrain\n",
    "cd uptrain\n",
    "bash run_uptrain.sh\n",
    "```\n",
    "\n",
    "This will start the UpTrain dashboard on your local machine. You can access it at `http://localhost:3000/dashboard`.\n",
    "\n",
    "Parameters:\n",
    "- key_type=\"openai\"\n",
    "- api_key=\"OPENAI_API_KEY\"\n",
    "- project_name=\"PROJECT_NAME\"\n",
    "\n",
    "\n",
    "### 2. **UpTrain Managed Service and Dashboards**:\n",
    "Alternatively, you can use UpTrain's managed service to evaluate your model. You can create a free UpTrain account [here](https://uptrain.ai/) and get free trial credits. If you want more trial credits, [book a call with the maintainers of UpTrain here](https://calendly.com/uptrain-sourabh/30min).\n",
    "\n",
    "The benefits of using the managed service are:\n",
    "1. No need to set up the UpTrain dashboard on your local machine.\n",
    "1. Access to many LLMs without needing their API keys.\n",
    "\n",
    "Once you perform the evaluations, you can view them in the UpTrain dashboard at `https://dashboard.uptrain.ai/dashboard`\n",
    "\n",
    "Parameters:\n",
    "- key_type=\"uptrain\"\n",
    "- api_key=\"UPTRAIN_API_KEY\"\n",
    "- project_name=\"PROJECT_NAME\"\n",
    "\n",
    "\n",
    "**Note:** The `project_name` will be the project name under which the evaluations performed will be shown in the UpTrain dashboard."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set the API key\n",
    "\n",
    "The notebook will prompt you to enter the API key. You can choose between the OpenAI API key or the UpTrain API key by changing the `key_type` parameter in the cell below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "KEY_TYPE = \"openai\"  # or \"uptrain\"\n",
    "API_KEY = getpass()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. Vanilla RAG"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "UpTrain callback handler will automatically capture the query, context and response once generated and will run the following three evaluations *(Graded from 0 to 1)* on the response:\n",
    "- **[Context Relevance](https://docs.uptrain.ai/predefined-evaluations/context-awareness/context-relevance)**: Check if the context extractedfrom the query is relevant to the response.\n",
    "- **[Factual Accuracy](https://docs.uptrain.ai/predefined-evaluations/context-awareness/factual-accuracy)**: Check how factually accurate the response is.\n",
    "- **[Response Completeness](https://docs.uptrain.ai/predefined-evaluations/response-quality/response-completeness)**: Check if the response contains all the information that the query is asking for."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m2024-04-17 17:03:44.969\u001b[0m | \u001b[1mINFO    \u001b[0m | \u001b[36muptrain.framework.evalllm\u001b[0m:\u001b[36mevaluate_on_server\u001b[0m:\u001b[36m378\u001b[0m - \u001b[1mSending evaluation request for rows 0 to <50 to the Uptrain\u001b[0m\n",
      "\u001b[32m2024-04-17 17:04:05.809\u001b[0m | \u001b[1mINFO    \u001b[0m | \u001b[36muptrain.framework.evalllm\u001b[0m:\u001b[36mevaluate\u001b[0m:\u001b[36m367\u001b[0m - \u001b[1mLocal server not running, start the server to log data and visualize in the dashboard!\u001b[0m\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Question: What did the president say about Ketanji Brown Jackson\n",
      "Response: The president mentioned that he had nominated Ketanji Brown Jackson to serve on the United States Supreme Court 4 days ago. He described her as one of the nation's top legal minds who will continue Justice Breyer’s legacy of excellence. He also mentioned that she is a former top litigator in private practice, a former federal public defender, and comes from a family of public school educators and police officers. He described her as a consensus builder and noted that since her nomination, she has received a broad range of support from various groups, including the Fraternal Order of Police and former judges appointed by both Democrats and Republicans.\n",
      "\n",
      "Context Relevance Score: 1.0\n",
      "Factual Accuracy Score: 1.0\n",
      "Response Completeness Score: 1.0\n"
     ]
    }
   ],
   "source": [
    "# Create the RAG prompt\n",
    "template = \"\"\"Answer the question based only on the following context, which can include text and tables:\n",
    "{context}\n",
    "Question: {question}\n",
    "\"\"\"\n",
    "rag_prompt_text = ChatPromptTemplate.from_template(template)\n",
    "\n",
    "# Create the chain\n",
    "chain = (\n",
    "    {\"context\": retriever, \"question\": RunnablePassthrough()}\n",
    "    | rag_prompt_text\n",
    "    | llm\n",
    "    | StrOutputParser()\n",
    ")\n",
    "\n",
    "# Create the uptrain callback handler\n",
    "uptrain_callback = UpTrainCallbackHandler(key_type=KEY_TYPE, api_key=API_KEY)\n",
    "config = {\"callbacks\": [uptrain_callback]}\n",
    "\n",
    "# Invoke the chain with a query\n",
    "query = \"What did the president say about Ketanji Brown Jackson\"\n",
    "docs = chain.invoke(query, config=config)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. Multi Query Generation\n",
    "\n",
    "The **MultiQueryRetriever** is used to tackle the problem that the RAG pipeline might not return the best set of documents based on the query. It generates multiple queries that mean the same as the original query and then fetches documents for each.\n",
    "\n",
    "To evluate this retriever, UpTrain will run the following evaluation:\n",
    "- **[Multi Query Accuracy](https://docs.uptrain.ai/predefined-evaluations/query-quality/multi-query-accuracy)**: Checks if the multi-queries generated mean the same as the original query."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m2024-04-17 17:04:10.675\u001b[0m | \u001b[1mINFO    \u001b[0m | \u001b[36muptrain.framework.evalllm\u001b[0m:\u001b[36mevaluate_on_server\u001b[0m:\u001b[36m378\u001b[0m - \u001b[1mSending evaluation request for rows 0 to <50 to the Uptrain\u001b[0m\n",
      "\u001b[32m2024-04-17 17:04:16.804\u001b[0m | \u001b[1mINFO    \u001b[0m | \u001b[36muptrain.framework.evalllm\u001b[0m:\u001b[36mevaluate\u001b[0m:\u001b[36m367\u001b[0m - \u001b[1mLocal server not running, start the server to log data and visualize in the dashboard!\u001b[0m\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Question: What did the president say about Ketanji Brown Jackson\n",
      "Multi Queries:\n",
      "  - How did the president comment on Ketanji Brown Jackson?\n",
      "  - What were the president's remarks regarding Ketanji Brown Jackson?\n",
      "  - What statements has the president made about Ketanji Brown Jackson?\n",
      "\n",
      "Multi Query Accuracy Score: 0.5\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m2024-04-17 17:04:22.027\u001b[0m | \u001b[1mINFO    \u001b[0m | \u001b[36muptrain.framework.evalllm\u001b[0m:\u001b[36mevaluate_on_server\u001b[0m:\u001b[36m378\u001b[0m - \u001b[1mSending evaluation request for rows 0 to <50 to the Uptrain\u001b[0m\n",
      "\u001b[32m2024-04-17 17:04:44.033\u001b[0m | \u001b[1mINFO    \u001b[0m | \u001b[36muptrain.framework.evalllm\u001b[0m:\u001b[36mevaluate\u001b[0m:\u001b[36m367\u001b[0m - \u001b[1mLocal server not running, start the server to log data and visualize in the dashboard!\u001b[0m\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Question: What did the president say about Ketanji Brown Jackson\n",
      "Response: The president mentioned that he had nominated Circuit Court of Appeals Judge Ketanji Brown Jackson to serve on the United States Supreme Court 4 days ago. He described her as one of the nation's top legal minds who will continue Justice Breyer’s legacy of excellence. He also mentioned that since her nomination, she has received a broad range of support—from the Fraternal Order of Police to former judges appointed by Democrats and Republicans.\n",
      "\n",
      "Context Relevance Score: 1.0\n",
      "Factual Accuracy Score: 1.0\n",
      "Response Completeness Score: 1.0\n"
     ]
    }
   ],
   "source": [
    "# Create the retriever\n",
    "multi_query_retriever = MultiQueryRetriever.from_llm(retriever=retriever, llm=llm)\n",
    "\n",
    "# Create the uptrain callback\n",
    "uptrain_callback = UpTrainCallbackHandler(key_type=KEY_TYPE, api_key=API_KEY)\n",
    "config = {\"callbacks\": [uptrain_callback]}\n",
    "\n",
    "# Create the RAG prompt\n",
    "template = \"\"\"Answer the question based only on the following context, which can include text and tables:\n",
    "{context}\n",
    "Question: {question}\n",
    "\"\"\"\n",
    "rag_prompt_text = ChatPromptTemplate.from_template(template)\n",
    "\n",
    "chain = (\n",
    "    {\"context\": multi_query_retriever, \"question\": RunnablePassthrough()}\n",
    "    | rag_prompt_text\n",
    "    | llm\n",
    "    | StrOutputParser()\n",
    ")\n",
    "\n",
    "# Invoke the chain with a query\n",
    "question = \"What did the president say about Ketanji Brown Jackson\"\n",
    "docs = chain.invoke(question, config=config)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3. Context Compression and Reranking\n",
    "\n",
    "The reranking process involves reordering nodes based on relevance to the query and choosing the top n nodes. Since the number of nodes can reduce once the reranking is complete, we perform the following evaluations:\n",
    "- **[Context Reranking](https://docs.uptrain.ai/predefined-evaluations/context-awareness/context-reranking)**: Check if the order of re-ranked nodes is more relevant to the query than the original order.\n",
    "- **[Context Conciseness](https://docs.uptrain.ai/predefined-evaluations/context-awareness/context-conciseness)**: Check if the reduced number of nodes still provides all the required information."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m2024-04-17 17:04:46.462\u001b[0m | \u001b[1mINFO    \u001b[0m | \u001b[36muptrain.framework.evalllm\u001b[0m:\u001b[36mevaluate_on_server\u001b[0m:\u001b[36m378\u001b[0m - \u001b[1mSending evaluation request for rows 0 to <50 to the Uptrain\u001b[0m\n",
      "\u001b[32m2024-04-17 17:04:53.561\u001b[0m | \u001b[1mINFO    \u001b[0m | \u001b[36muptrain.framework.evalllm\u001b[0m:\u001b[36mevaluate\u001b[0m:\u001b[36m367\u001b[0m - \u001b[1mLocal server not running, start the server to log data and visualize in the dashboard!\u001b[0m\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Question: What did the president say about Ketanji Brown Jackson\n",
      "\n",
      "Context Conciseness Score: 0.0\n",
      "Context Reranking Score: 1.0\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m2024-04-17 17:04:56.947\u001b[0m | \u001b[1mINFO    \u001b[0m | \u001b[36muptrain.framework.evalllm\u001b[0m:\u001b[36mevaluate_on_server\u001b[0m:\u001b[36m378\u001b[0m - \u001b[1mSending evaluation request for rows 0 to <50 to the Uptrain\u001b[0m\n",
      "\u001b[32m2024-04-17 17:05:16.551\u001b[0m | \u001b[1mINFO    \u001b[0m | \u001b[36muptrain.framework.evalllm\u001b[0m:\u001b[36mevaluate\u001b[0m:\u001b[36m367\u001b[0m - \u001b[1mLocal server not running, start the server to log data and visualize in the dashboard!\u001b[0m\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Question: What did the president say about Ketanji Brown Jackson\n",
      "Response: The President mentioned that he nominated Circuit Court of Appeals Judge Ketanji Brown Jackson to serve on the United States Supreme Court 4 days ago. He described her as one of the nation's top legal minds who will continue Justice Breyer’s legacy of excellence.\n",
      "\n",
      "Context Relevance Score: 1.0\n",
      "Factual Accuracy Score: 1.0\n",
      "Response Completeness Score: 0.5\n"
     ]
    }
   ],
   "source": [
    "# Create the retriever\n",
    "compressor = FlashrankRerank()\n",
    "compression_retriever = ContextualCompressionRetriever(\n",
    "    base_compressor=compressor, base_retriever=retriever\n",
    ")\n",
    "\n",
    "# Create the chain\n",
    "chain = RetrievalQA.from_chain_type(llm=llm, retriever=compression_retriever)\n",
    "\n",
    "# Create the uptrain callback\n",
    "uptrain_callback = UpTrainCallbackHandler(key_type=KEY_TYPE, api_key=API_KEY)\n",
    "config = {\"callbacks\": [uptrain_callback]}\n",
    "\n",
    "# Invoke the chain with a query\n",
    "query = \"What did the president say about Ketanji Brown Jackson\"\n",
    "result = chain.invoke(query, config=config)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# UpTrain's Dashboard and Insights\n",
    "\n",
    "Here's a short video showcasing the dashboard and the insights:\n",
    "\n",
    "![langchain_uptrain.gif](https://uptrain-assets.s3.ap-south-1.amazonaws.com/images/langchain/langchain_uptrain.gif)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
